import { Injectable } from '@nestjs/common';
import { CreateStageDto } from './dto/create-stage.dto';
import { UpdateStageDto } from './dto/update-stage.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Stage } from './entities/stage.entity';
import { Repository } from 'typeorm';
import {
  GroupStatusEnum,
  MatchStatusEnum,
  StageStatusEnum,
} from 'src/common/constant/enums';
import logger from 'src/common/utils/log';
import { User } from '../user/entities/user.entity';

@Injectable()
export class StageService {
  constructor(
    @InjectRepository(Stage)
    private readonly repository: Repository<Stage>,
  ) {}

  async create(createStageDto: Partial<CreateStageDto>) {
    const entity = this.repository.create(createStageDto);
    return await this.repository.save(entity);
  }

  async saveList(createStageDtoList: Array<Partial<CreateStageDto>>) {
    const entities = createStageDtoList.map((v) => {
      return this.repository.create(v);
    });
    return await this.repository.save(entities);
  }

  async findOne(id: number) {
    return await this.repository.findOne({ where: { id: id } });
  }

  async update(id: number, updateStageDto: UpdateStageDto) {
    return await this.repository.update(id, updateStageDto);
  }

  async remove(id: number) {
    return await this.removeIds([id]);
  }

  async removeIds(ids: number[]) {
    return await this.repository.delete(ids);
  }

  async getDetail(id: number) {
    return await this.repository.findOne({
      where: { id: id },
      relations: ['groups', 'groups.matchInfos'],
    });
  }
  async listByTournamentIdForDelete(tournamentId: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('matchInfos.winner', 'winner')
      .leftJoinAndSelect('matchInfos.homePlayer', 'homePlayer')
      .leftJoinAndSelect('matchInfos.awayPlayer', 'awayPlayer')
      .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
      .leftJoinAndSelect('subMatchInfos.winner', 'subWinner')
      .leftJoinAndSelect('subMatchInfos.homePlayer', 'subHomePlayer')
      .leftJoinAndSelect('subMatchInfos.awayPlayer', 'subAwayPlayer')
      .leftJoinAndSelect('matchInfos.games', 'games')
      .leftJoinAndSelect('subMatchInfos.games', 'subGames')
      .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      .where('stage.tournamentId = :tournamentId', { tournamentId })
      .getMany();
  }
  async getAllUnfinishedStageMatches(id: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .where('stage.id = :id', { id })
      .andWhere('matchInfos.status != :status', {
        status: MatchStatusEnum.Finished,
      })
      .getMany();
  }
  async getStageProcessInfo(id: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .where('stage.id = :id', { id })
      .getOne();
  }
  async getByEventIdAndStageOrder(eventId: number, stageOrderInEvent: number) {
    // console.log(3333, stageOrderInEvent, eventId);
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      // .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
      .where('stage.eventId = :eventId', { eventId })
      .andWhere('stage.stageOrderInEvent = :stageOrderInEvent', {
        stageOrderInEvent,
      })
      .getOne();
  }
  async getNextStage(eventId: number, stageOrderInEvent: number) {
    // console.log(3333, stageOrderInEvent, eventId);
    let nextStage = null;
    const nextStages = await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      // .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
      .where('stage.eventId = :eventId', { eventId })
      .andWhere('stage.stageOrderInEvent >= :stageOrderInEvent', {
        stageOrderInEvent,
      })
      .orderBy('stage.stageOrderInEvent', 'ASC')
      .getMany();
    if (nextStages && nextStages.length) {
      nextStage = nextStages[0];
    }
    return nextStage;
  }
  async getByMatchId(matchId: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      .where('matchInfos.id = :matchId', { matchId })
      .getOne();
  }
  async getStageDetail(stageId: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('matchInfos.winner', 'winner')
      .leftJoinAndSelect('matchInfos.homePlayer', 'homePlayer')
      .leftJoinAndSelect('matchInfos.awayPlayer', 'awayPlayer')
      .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
      .leftJoinAndSelect('subMatchInfos.winner', 'subWinner')
      .leftJoinAndSelect('subMatchInfos.homePlayer', 'subHomePlayer')
      .leftJoinAndSelect('subMatchInfos.awayPlayer', 'subAwayPlayer')
      .leftJoinAndSelect('matchInfos.games', 'games')
      .leftJoinAndSelect('subMatchInfos.games', 'subGames')
      .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      .where('stage.id = :stageId', { stageId })
      .getOne();
  }
  async getStageDetailForCopy(stageId: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
      .leftJoinAndSelect('matchInfos.homePlayer', 'homePlayer')
      .leftJoinAndSelect('matchInfos.awayPlayer', 'awayPlayer')
      // .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
      // .leftJoinAndSelect('subMatchInfos.homePlayer', 'subHomePlayer')
      // .leftJoinAndSelect('subMatchInfos.awayPlayer', 'subAwayPlayer')
      // .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      // .leftJoinAndSelect('groupPlayerScores.player', 'scorePlayer')
      // .leftJoinAndSelect('matchInfos.games', 'games')
      .where('stage.id = :stageId', { stageId })
      .getOne();
  }
  // async getStageMatches(stageId: number) {
  //   return await this.repository
  //     .createQueryBuilder('stage')
  //     .select(['stage.id', 'stage.name'])
  //     .leftJoinAndSelect('stage.groups', 'groups')
  //     .leftJoinAndSelect('groups.matchInfos', 'matchInfos')
  //     .leftJoinAndSelect('matchInfos.homePlayer', 'homePlayer')
  //     .leftJoinAndSelect('matchInfos.awayPlayer', 'awayPlayer')
  //     .leftJoinAndSelect('matchInfos.subMatchInfos', 'subMatchInfos')
  //     .leftJoinAndSelect('subMatchInfos.homePlayer', 'subHomePlayer')
  //     .leftJoinAndSelect('subMatchInfos.awayPlayer', 'subAwayPlayer')
  //     .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
  //     .leftJoinAndSelect('groupPlayerScores.player', 'scorePlayer')
  //     .leftJoinAndSelect('matchInfos.games', 'games')
  //     .leftJoinAndSelect('subMatchInfos.games', 'subGames')
  //     .where('stage.id = :stageId', { stageId })
  //     .getOne();
  // }
  async listBySourcePlayerStageId(sourcePlayerStageId: number) {
    const qb = this.repository
      .createQueryBuilder('stage')
      .where('stage.playerSourceStageId = :sourcePlayerStageId', {
        sourcePlayerStageId,
      })
      .andWhere(
        `stage.stageOrderInEvent > (${this.repository
          .createQueryBuilder('stage')
          .select('stage.stageOrderInEvent')
          .where('stage.id = :sourcePlayerStageId', { sourcePlayerStageId })
          .getQuery()})`,
      );
    return await qb.getMany();
  }
  async getByIdWithGroupDetails(stageId: number) {
    return await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      .leftJoinAndSelect('stage.groups', 'groups')
      .leftJoinAndSelect('groups.groupPlayerScores', 'groupPlayerScores')
      .where('stage.id = :stageId', { stageId })
      .getOne();
  }
  async checkFinish(id: number) {
    logger.info('finishStage...', id);
    const { groups } = await this.repository.findOne({
      where: { id },
      relations: ['groups'],
    });
    const isAllFinished = groups.every(
      (group) => group.status === GroupStatusEnum.Finished,
    );
    if (isAllFinished) {
      await this.update(id, {
        status: StageStatusEnum.Finished,
      });
    }
    logger.info('finishStage...', id, isAllFinished);
    return isAllFinished;
  }
  mapStageToCreateDto(stage: Stage): Partial<CreateStageDto> {
    const {
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      id,
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      createBy,
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      updateBy,
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      // 其他不需要复制的字段
      ...rest
    } = stage;
    const res: Partial<CreateStageDto> = { ...rest } as any;
    res.fkEventId = rest.eventId;
    return res;
  }

  /**
   * 根据 id 查询 Stage
   */
  async findByIdForCopy(stageId: number): Promise<Stage | undefined> {
    // return this.repository.findOne(stageId, { relations: ['stageEvents'] });
    const res = await this.repository
      .createQueryBuilder('stage')
      .leftJoinAndSelect('stage.stageEvents', 'stageEvents')
      // .leftJoinAndSelect('stage.event', 'event')
      .where({ id: stageId })
      .getOne();

    return res;
  }

  async copyStage(
    stageId: number,
    isCopySchedule: boolean,
    isCopyE2P: boolean,
    user: User,
  ) {
    logger.info('copyStage is out of service temporarily');
    // // 1. 通过 stageId 获取原 stage 配置
    // const originalStage = await this.findByIdForCopy(stageId);
    // if (!originalStage) {
    //   throw new HttpException(
    //     '原始阶段不存在',
    //     HttpStatus.INTERNAL_SERVER_ERROR,
    //   );
    // }

    // // 2. 调用创建 stage 的方法，创建新的 stage
    // // 这里复用 create 方法，传入原 stage 的配置（去除id等不可复制字段）
    // const createStageDto = this.mapStageToCreateDto(originalStage);
    // createStageDto.createBy = user.id;
    // createStageDto.updateBy = user.id;
    // createStageDto.name = `${originalStage.name}（复制）`;
    // const newStage = await this.create(createStageDto);

    // if (isCopyE2P) {
    //   // 3. 复制原 stage 的 E2P 数据
    //   const originalE2Ps =
    //     await this.eventToPlayerService.findByStageId(stageId);

    //   // 4. 根据 registrationIndex 绑定 player 到新的 E2P
    //   // 先获取新 stage 的 E2P 列表
    //   const newE2Ps = await this.eventToPlayerService.findByStageId(
    //     newStage.id,
    //   );

    //   // 构造绑定参数列表
    //   const bindParams = [];
    //   for (const newE2P of newE2Ps) {
    //     const matchedOldE2P = originalE2Ps.find(
    //       (e) => e.registrationIndex === newE2P.registrationIndex,
    //     );
    //     if (matchedOldE2P) {
    //       bindParams.push({
    //         id: newE2P.id,
    //         playerId: matchedOldE2P.player1Id,
    //         player2Id: matchedOldE2P.player2Id,
    //         isByePlayer: matchedOldE2P.isByePlayer,
    //         player1Name: matchedOldE2P.player1Name,
    //         player2Name: matchedOldE2P.player2Name,
    //       });
    //     }
    //   }

    //   // 5. 调用绑定球员的服务，复用已有逻辑
    //   await this.bingPlayerService.bindPlayerToE2P(bindParams);
    // }
    // if (isCopySchedule) {
    //   const originMatches = await this.matchService.getByStageId(stageId);
    //   const newMatches = await this.matchService.getByStageId(newStage.id);
    //   for (const newMatch of newMatches) {
    //     const matchedOldMatch = originMatches.find(
    //       (e) => e.groupMatchIndex === newMatch.groupMatchIndex,
    //     );
    //     if (matchedOldMatch) {
    //       newMatch.playgroundId = matchedOldMatch.playgroundId;
    //       newMatch.estimatedStart = matchedOldMatch.estimatedStart;
    //       newMatch.estimatedEnd = matchedOldMatch.estimatedEnd;
    //     }
    //   }
    //   await this.matchService.saveList(newMatches);
    // }

    // return {
    //   message: '复制阶段成功',
    //   newStage,
    // };
  }
  listByEventId(eventId: number) {
    return this.repository.find({
      where: { eventId },
    });
  }
}
